package com.treasury.glasses.controller.helper;

import com.treasury.glasses.Main;
import com.treasury.glasses.persistence.FileAccess;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;

/**
 * Manager for the ActivityMenu.
 * @author <a href="mailto:glasses@audienz.eu">Jean-Luc Burot</a>
 */

public class ActiveMenuManager {
    private final TreeView<String> view;
    private final BorderPane container;
    private final List<ActiveMenuItemable> masks;
    
    public ActiveMenuManager(TreeView<String> view, final BorderPane container) {
        // Initialize and instantiate
        this.view = view;
        this.container = container;
        this.masks = new ArrayList<>();
        
        // Create Root item in the view and expand it.
        this.view.setRoot(new TreeItem<>("Masks"));
        this.view.getRoot().setExpanded(true);
        
        // Create an event listener for the ActiveMenu.
        this.view.getSelectionModel().selectedItemProperty().addListener( new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                setContainer((TreeItem<String>) newValue);
            }
        });
    }
    
    public void setMask(MaskPath maskPath) throws IOException {
        
        // If the mask is already in use then reload it.
        // Otherwise create a new one.
        ActiveMenuItemable ami = findMask(maskPath);

        // Check if mask found.
        if (ami == null) {
            // Create mask.
            ami = createActiveMenuItem(maskPath);
            
            // Add mask.
            this.masks.add(ami);
        }
        
        // Add an item to the view.
        setView(ami);
        
        // Select the item.
        selectActiveMenuItem(maskPath);
    }
    
    public void delMask(MaskPath maskPath) throws IOException {
        // Get ActiveMenuItem.
        ActiveMenuItemable ami = findMask(maskPath);
        
        System.out.println("delMask : this.masks : " + this.masks);
        System.out.println("ami : " + ami);
        // Remove view item.
        this.masks.remove(ami);
        
        // Remove an item from the view.
        delView(ami);
        
        // Select another active mask.
        setContainer(null);
    }
    
    private void setView(ActiveMenuItemable ami) {
        // Check if view active.
        if (this.container.getLeft() != null) {
            
            System.out.println("ami : " + ami);
            System.out.println("ami.getTreeItem() : " + ami.getTreeItem());
            // Add item to view.
            this.view.getRoot().getChildren().add(ami.getTreeItem());
        }
    }
    
    private void delView(ActiveMenuItemable ami) {
        // Check if view active.
        if (this.container.getLeft() != null) {
            // Delete item from view.
            this.view.getRoot().getChildren().remove(ami.getTreeItem());
        }
    }
    
    private void setContainer(TreeItem<String> item) {
        // Check if item is null.
        if (item == null) {
            // Empty container.
            this.container.setCenter(null);
        } else {
            // Walk through all the entries in the masks list.
            for (ActiveMenuItemable ami : this.masks) {
                // Check if entry matches TreeItem argument.
                if (item.equals(ami.getTreeItem())) {
                    // Set the mask to the container.
                    this.container.setCenter(ami.getMask());

                    // End this loop as job is done.
                    break;
                }
            }
        }
    }
    
    private ActiveMenuItemable findMask(MaskPath maskPath) {
        // Define the response.
        ActiveMenuItemable amiOut = null;
        
        // Walk through all the entries in the masks list.
        for (ActiveMenuItemable ami : this.masks) {
            // Compare the searched MaskPath with the list of active ones.
            if (maskPath.equals(ami.getMaskPath())) {
                // Found a match.
                amiOut = ami;
                
                // End this loop as job is done.
                break;
            }
        }
        
        // Return the response.
        return amiOut;
    }
    
    private ActiveMenuItemable createActiveMenuItem(MaskPath maskPath) throws IOException {
        // If mask already in use, then make visible.
        ActiveMenuItemable ami = new ActiveMenuItem();
        
        // Load mask.
        FileAccess fileAccess = Main.getFileAccess();
        FXMLLoader loader = fileAccess.getFXML(maskPath.toString());
        Pane mask = (Pane) loader.getRoot();
        Maskable controller = loader.getController();

        // Create ActiveMenuItem.
        ami.setMask(mask);
        ami.setController(controller);
        ami.setTreeItem(new TreeItem<>(controller.getName()));
        ami.setMaskPath(maskPath);
        
        // Return created item.
        return ami;
    }
    
    private void selectActiveMenuItem(MaskPath maskPath) {
        // Find mask.
        ActiveMenuItemable ami = findMask(maskPath);
        // When container is not active set it using the method,
        // otherwise use the parameter triggering the change event.
        if (this.container.getLeft() == null) {
            // Set the container using the method.
            setContainer(ami.getTreeItem());
        } else {
            // Set parameter triggering for the change event.
            this.view.getSelectionModel().select(ami.getTreeItem());
        }
    }
    
    /*
    private boolean itemExistsInActiveMenu(TreeItem<String> entry) {
        // Return value defaults false.
        boolean exists = false;
        
        // Compare all ActiveMenu items with the entry.
        for (int i = 0; i < this.activeMenu.getRoot().getChildren().size(); i++) {
            // Check if entry is equal to ActiveMenu item.
            if (entry.equals(this.activeMenu.getRoot().getChildren().get(i))) {
                // Entry found in ActiveMenu.
                exists = true;
                break;
            }
        }
        
        return exists;
    }
    */
     
    /*
    private void loadActiveMenu() {
        // Empty the active menu.
        this.activeMenu.getRoot().getChildren().clear();
        
        // Go through all the entries in the masks Map and add only new ones.
        for (Map.Entry<MaskPath, ActiveMenuItemable> entry : this.masks.entrySet()) {
            // Add one TreeItem to the ActiveMenu.
            this.activeMenu.getRoot().getChildren().add(entry.getValue().getTreeItem());
        }
    }
    */
    
    /*
    public void removeItem(Maskable mask) {
        // Search appropriate TreeItem.
        for (List<Object> maskComponents : this.masks) {
            if (maskComponents.get(0) == mask) {
                // Delete mask from TreeView.
                this.activity.getRoot().getChildren().remove((TreeItem<String>) maskComponents.get(1));
                
                // Delete mask from list of masks.
                this.masks.remove(maskComponents);
                
                // Go out of loop. Work done.
                break;
            }
        }
    }
    */
    
    /*
    private void loadMask(TreeItem<String> node) throws IOException {
        // Go through all the entries in the masks Map.
        for (Map.Entry<MaskPath, ActiveMenuItemable> entry : this.masks.entrySet()) {
            // Check if entry matches node argument.
            if (node.equals(entry.getValue().getTreeItem())) {
                // Load the appropriate mask.
                loadMask(entry.getKey());
                break;
            }
        }
    }
    */
}
